﻿using JV.Com.Business;
using JV.Com.Internals;
using JV.Com.ViewModels;
using JV.Com.ViewModels.Wrapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

namespace JV.Com.Tools
{
    public interface IHTMLInline
    {
        void Prepare();
        Inline ToInline();
    }

    public abstract class HTMLInlineUIContainer : IHTMLInline
    {
        public abstract InlineUIContainer ToInlineUIContainer();

        public Inline ToInline()
        {
            return ToInlineUIContainer();
        }

        public virtual void Prepare()
        {
            // Nothing
        }
    }

    public abstract class HTMLText : IHTMLInline
    {
        public static HTMLInlineCollection ConvertToParagraph(string text)
        {
            var inlines = new HTMLInlineCollection();
            var currentText = new StringBuilder();
            for (int i = 0; i < text.Length; i++)
            {
                var c = text[i];
                if (c == '\n')
                {
                    if (currentText.Length > 0)
                    {
                        var run = new HTMLDefaultText() { Text = currentText.ToString() };
                        inlines.AddInline(run);
                        currentText.Clear();
                    }
                    inlines.AddLineBreak();
                    continue;
                }
                currentText.Append(c);
            }

            {
                if (currentText.Length > 0)
                {
                    var run = new HTMLDefaultText() { Text = currentText.ToString() };
                    inlines.AddInline(run);
                }
            }

            return inlines;
        }

        public string Text { get; set; }

        public abstract Inline ToInline();

        public virtual void Prepare()
        {
            // Nothing
        }
    }

    public class HTMLLineBreak : IHTMLInline
    {
        public Inline ToInline()
        {
            return new LineBreak();
        }

        public void Prepare()
        {
            // Nothing
        }
    }

    #region HTMLHyperLink

    #endregion

    #region HTMLInlineCollection
    public sealed class HTMLInlineCollection : IEnumerable<IHTMLInline>
    {
        private readonly List<IHTMLInline> m_inlines;
        public HTMLInlineCollection()
        {
            m_inlines = new List<IHTMLInline>();
        }

        public void AddInline(IHTMLInline inline)
        {
            if (inline is HTMLLineBreak)
            {
                AddLineBreak();
            }
            else
            {
                m_inlines.Add(inline);
            }
        }

        private int m_totalPageFolder;
        public int TotalPageFolder { get { return m_totalPageFolder; } }

        public void AddLineBreak()
        {
            if(m_inlines.Count > 2)
            {
                var length = m_inlines.Count;
                if(m_inlines[length - 1] is HTMLLineBreak && m_inlines[length - 2] is HTMLLineBreak)
                {
                    return;
                }
            }

            m_inlines.Add(new HTMLLineBreak());
        }

        public Paragraph ToParagraph()
        {
            var paragraph = new Paragraph();
            foreach(var inline in m_inlines)
            {
                paragraph.Inlines.Add(inline.ToInline());
            }
            return paragraph;
        }

        public void Process()
        {
            // Prepare
            foreach(var inline in m_inlines)
            {
                inline.Prepare();
            }

            // Suppression des premiers linebreak potentiel
            while (m_inlines.Count > 0 && m_inlines[0] is HTMLLineBreak)
            {
                m_inlines.RemoveAt(0);
            }

            // 0. Récupérations générales
            foreach(var inline in m_inlines)
            {
                if(inline is HTMLHyperLink)
                {
                    var hyperlink = (HTMLHyperLink)inline;
                    if(hyperlink.NavType == NavType.Folder)
                    {
                        m_totalPageFolder = Math.Max(m_totalPageFolder, ((FolderPageNavigationParameter)hyperlink.NavParameter).FolderPage);
                    }
                }
            }

            var newInlines = new List<IHTMLInline>();
            var totalCount = m_inlines.Count;

            // 1. Suppression des espaces devant le début des paragraphes
            for (int i = 0; i < totalCount; i++)
            {
                var inline = m_inlines[i];

                if (i > 0 && !(m_inlines[i - 1] is HTMLText) && inline is HTMLText)
                {
                    var text = (HTMLText)inline;
                    text.Text = text.Text.TrimStart();
                }
            }

            // 2. Faire float les images
            for (int i = 0; i < totalCount; i++)
            {
                var inline = m_inlines[i];

                if (inline is HTMLImage && ((HTMLImage)inline).FloatingValue != HTMLImageFloating.None)
                {
                    var j = i + 1;
                    var textCollection = new HTMLTextCollection();
                    while (j < totalCount && !(m_inlines[j] is HTMLLineBreak))
                    {
                        textCollection.AddText((HTMLText)m_inlines[j]);
                        m_inlines.RemoveAt(j);
                        totalCount--;
                    }

                    var image = inline as HTMLImage;
                    if (textCollection.Any())
                    {
                        inline = new HTMLFloatingPanel() { Image = image, Text = textCollection };
                    }
                }

                newInlines.Add(inline);
            }

            m_inlines.Clear();
            m_inlines.AddRange(newInlines);
        }

        public IEnumerator<IHTMLInline> GetEnumerator()
        {
            return m_inlines.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return m_inlines.GetEnumerator();
        }
    }
    #endregion

    #region HTMLMediaElement
    public class HTMLMediaElement : HTMLInlineUIContainer
    {
        public string VideoUrl { get; set; }
        public string ImageUrl { get; set; }

        enum QualityType
        {
            tLow,
            tHigh,
            t720p,
            t1080p
        }

        private class QualityLink
        {
            public string Title { get; set; }
            public QualityType Type { get; set; }
            public string Url { get; set; }
        }

        private TimeSpan m_currentMePosition;
        private bool m_firstTime;
        public override InlineUIContainer ToInlineUIContainer()
        {
            m_firstTime = true;

            var me = new Windows.UI.Xaml.Controls.MediaElement();
            me.AutoPlay = false;
            me.AreTransportControlsEnabled = true;
            me.Height = 290;
            me.Width = 510;
            me.Margin = new Thickness(0, 5, 0, 5);
            me.Source = new Uri(VideoUrl);
            //me.Source = new Uri(VideoUrl + "low.mp4");

            //var qualityPanel = new StackPanel() { Orientation = Orientation.Vertical };

            //var qualityLinks = new List<QualityLink>();

            //var url = VideoUrl + "low.mp4";
            //if (Task.Run(async () => await HttpService.IsUrlValid(url)).Result)
            //{
            //    qualityLinks.Add(new QualityLink() { Title = "Basse", Type = QualityType.tLow, Url = url });
            //}

            //url = VideoUrl + "high.mp4";
            //if (Task.Run(async () => await HttpService.IsUrlValid(url)).Result)
            //{
            //    qualityLinks.Add(new QualityLink() { Title = "Haute", Type = QualityType.tLow, Url = url });
            //}

            //url = VideoUrl + "720p.mp4";
            //if (Task.Run(async () => await HttpService.IsUrlValid(url)).Result)
            //{
            //    qualityLinks.Add(new QualityLink() { Title = "720p", Type = QualityType.tLow, Url = url });
            //}

            //url = VideoUrl + "1080p.mp4";
            //if (Task.Run(async () => await HttpService.IsUrlValid(url)).Result)
            //{
            //    qualityLinks.Add(new QualityLink() { Title = "1080p", Type = QualityType.tLow, Url = url });
            //}

            //me.SeekCompleted += (s2, e2) =>
            //{
            //    if (!m_firstTime)
            //    {
            //        me.Play();
            //    }
            //    else
            //    {
            //        m_firstTime = false;
            //    }
            //};

            //me.MediaOpened += (s1, e1) =>
            //{
            //    me.Position = m_currentMePosition;
            //};

            //foreach(var qualityLink in qualityLinks)
            //{
            //    var button = new HyperlinkButton() { Content = qualityLink.Title };
            //    button.Click += (s, e) =>
            //        {
            //            me.Pause();
            //            m_currentMePosition = me.Position;
            //            me.Source = new Uri(qualityLink.Url);
            //        };
            //    qualityPanel.Children.Add(button);
            //}

            //var bigPanel = new StackPanel() { Orientation = Orientation.Horizontal};
            //bigPanel.Children.Add(me);
            //bigPanel.Children.Add(qualityPanel);
            
            var container = new InlineUIContainer();
            container.Child = me;
            return container;
        }
    }
    #endregion

    #region HTMLFloatingPanel
    public class HTMLFloatingPanel : HTMLInlineUIContainer
    {
        public HTMLImage Image { get; set; }
        public HTMLTextCollection Text { get; set; }

        public override InlineUIContainer ToInlineUIContainer()
        {
            var imageUI = Image.ToUIElementButtonized();
            var textUI = Text.ToUIElement();

            var grid = new Grid();
            grid.Children.Add(imageUI);
            grid.Children.Add(textUI);

            if (Image.FloatingValue == HTMLImageFloating.Left)
            {
                grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
                grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
                Grid.SetColumn(textUI, 1);
            }
            else
            {
                grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
                grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
                Grid.SetColumn(imageUI, 1);
            }

            var container = new InlineUIContainer();
            container.Child = grid;
            return container;
        }
    }
    #endregion

    #region HTMLImage
    public enum HTMLImageFloating
    {
        None,
        Left,
        Right
    }
    public class HTMLImage : HTMLInlineUIContainer
    {
        public string ImageUrl { get; set; }
        public string LargeImageUrl { get; set; }
        public HTMLImageFloating FloatingValue { get; set; }

        public Windows.UI.Xaml.Controls.Image ToUIElement()
        {
            var bi = new BitmapImage(new Uri(ImageUrl));
            var image = new Windows.UI.Xaml.Controls.Image();
            image.Stretch = Windows.UI.Xaml.Media.Stretch.None;
            image.Source = bi;
            image.VerticalAlignment = VerticalAlignment.Top;
            return image;
        }

        public Windows.UI.Xaml.FrameworkElement ToUIElementButtonized()
        {
            var image = ToUIElement();
            var button = new Button();
            var grid = new Grid();
            button.Opacity = 0;

            button.PointerEntered += (s, e) =>
                {
                    Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.Hand, 1);
                };
            button.PointerExited += (s, e) =>
                {
                    Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.Arrow, 1);
                };

            button.HorizontalAlignment = HorizontalAlignment.Stretch;
            button.VerticalAlignment = VerticalAlignment.Stretch;
            button.Click += (s, e) =>
                {
                    var context = button.DataContext as PageBaseViewModel;
                    // TODO
                    //context.GetMainNavigationService().Navigate("FlipViewFullScreen", LargeImageUrl);
                };
            if(FloatingValue == HTMLImageFloating.Left)
            {
                image.Margin = new Thickness(0, 0, 10, 0);
            }
            else if(FloatingValue == HTMLImageFloating.Right)
            {
                image.Margin = new Thickness(10, 0, 0, 0);
            }
            else
            {
                image.Margin = new Thickness(0, 0, 5, 5);
            }
            grid.Children.Add(image);
            grid.Children.Add(button);
            return grid;
        }

        public override InlineUIContainer ToInlineUIContainer()
        {
            var button = ToUIElementButtonized();
            var container = new InlineUIContainer();
            container.Child = button;
            return container;
        }
    }
    

    public class HTMLImageCollection : HTMLInlineUIContainer, IEnumerable<HTMLImage>
    {
        private readonly List<HTMLImage> m_images;
        public HTMLImageCollection()
        {
            m_images = new List<HTMLImage>();
        }

        public void AddImage(HTMLImage image)
        {
            m_images.Add(image);
        }

        public IEnumerator<HTMLImage> GetEnumerator()
        {
            return m_images.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return m_images.GetEnumerator();
        }

        public override InlineUIContainer ToInlineUIContainer()
        {
            var itemsControl = new ItemsControl();
            itemsControl.HorizontalAlignment = HorizontalAlignment.Left;

            var builderTemplate = new StringBuilder();
            builderTemplate.AppendLine("<ItemsPanelTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">");
            builderTemplate.AppendLine("<ItemsWrapGrid Orientation=\"Horizontal\" />");
            builderTemplate.AppendLine("</ItemsPanelTemplate>");
            itemsControl.ItemsPanel = (ItemsPanelTemplate)XamlReader.Load(builderTemplate.ToString());

            foreach(var image in m_images)
            {
                itemsControl.Items.Add(image.ToUIElementButtonized());
            }

            var container = new InlineUIContainer();
            container.Child = itemsControl;
            return container;
        }
    }
    #endregion

    #region HTMLTitle
    public class HTMLTitle : HTMLInlineUIContainer
    {
        public enum Importance
        {
            Big,
            Medium
        }

        public Importance ImportanceValue { get; set; }
        public string Text { get; set; }
        public override InlineUIContainer ToInlineUIContainer()
        {
            var tb = new TextBlock();
            tb.Text = Text;
            switch(ImportanceValue)
            {
                case Importance.Big: tb.FontSize = 17; break;
                case Importance.Medium: tb.FontSize = 15; break;
                default: throw new NotImplementedException();
            }
            tb.FontWeight = FontWeights.Black;
            tb.Margin = new Thickness(0, 10, 0, 10);
            var UIinline = new InlineUIContainer();
            UIinline.Child = tb;
            return UIinline;
        }
    }
    #endregion

    #region HTMLText
    public class HTMLTextCollection : HTMLInlineUIContainer, IEnumerable<HTMLText>, IHTMLInline
    {
        private readonly List<HTMLText> m_texts;
        public HTMLTextCollection()
        {
            m_texts = new List<HTMLText>();
        }

        public void AddText(HTMLText text)
        {
            m_texts.Add(text);
        }

        public IEnumerator<HTMLText> GetEnumerator()
        {
            return m_texts.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return m_texts.GetEnumerator();
        }

        public override InlineUIContainer ToInlineUIContainer()
        {
            var text = ToUIElement();
            var container = new InlineUIContainer();
            container.Child = text;
            return container;
        }

        public RichTextBlock ToUIElement()
        {
            var text = new RichTextBlock();
            text.Style = Application.Current.Resources["RichTextBlockDefaultStyle"] as Style;
            var tmpParagraph = new Paragraph();
            foreach (var textToWrap in m_texts)
            {
                tmpParagraph.Inlines.Add(textToWrap.ToInline());
            }
            text.Blocks.Add(tmpParagraph);
            return text;
        }
    }

    public class HTMLDefaultText : HTMLText
    {
        public override Inline ToInline()
        {
            var run = new Run();
            run.Text = Text;
            run.FontWeight = FontWeights.Normal;
            return run;
        }
    }

    public class HTMLStrongText : HTMLText
    {
        public override Inline ToInline()
        {
            var run = new Run();
            run.Text = Text;
            run.FontWeight = FontWeights.Bold;
            return run;
        }
    }

    public enum NavType
    {
        Search,
        News,
        Test,
        Preview,
        Folder,
        Web,
        Game
    }

    public class HTMLHyperLink : HTMLText
    {
        public string Url { get; set; }

        public NavType NavType { get; set; }

        public object NavParameter { get; set; }

        public override void Prepare()
        {
            if (Url.StartsWith("http"))
            {
                NavType = Tools.NavType.Web;
            }
            else
            {
                var url = Url.Remove(0, 5);

                if (url.StartsWith("search"))
                {
                    var terms = Uri.UnescapeDataString(url.Split('/')[1]);
                    NavType = Tools.NavType.Search;
                    NavParameter = terms;
                }
                else if (url.StartsWith("01.jeux"))
                {
                    var gameId = int.Parse(url.Split('/')[1].Split('.')[0]);
                    NavType = Tools.NavType.Game;
                    NavParameter = gameId;
                }
                else if (url.StartsWith("03.preview"))
                {
                    var previewId = int.Parse(url.Split('/')[1].Split('.')[0]);
                    NavType = Tools.NavType.Preview;
                    NavParameter = previewId;
                }
                else if (url.StartsWith("02.news"))
                {
                    var newsId = int.Parse(url.Split('/')[1].Split('.')[0]);
                    NavType = Tools.NavType.News;
                    NavParameter = newsId;
                }
                else if (url.StartsWith("03.test"))
                {
                    var testId = int.Parse(url.Split('/')[1].Split('.')[0]);
                    NavType = Tools.NavType.Test;
                    NavParameter = testId;
                }
                else if (url.StartsWith("03.dossier"))
                {
                    var ids = url.Split('/');
                    var folderId = int.Parse(ids[1].Split('.')[0]);
                    int folderPage = 0;
                    if (ids.Length > 2) folderPage = int.Parse(ids[2].Split('.')[0]);
                    NavType = Tools.NavType.Folder;
                    NavParameter = new FolderPageNavigationParameter() { FolderId = folderId, FolderPage = folderPage };
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
        }

        public override Inline ToInline()
        {
            var tb = new TextBlock();
            var hyperlink = new Hyperlink();
            hyperlink.Inlines.Add(new HTMLDefaultText() { Text = Text }.ToInline());
            tb.Inlines.Add(hyperlink);

            switch (NavType)
            {
                case Tools.NavType.Web:
                    hyperlink.Inlines.Insert(0, new Run() { Text = "\uE128 ", FontFamily = new FontFamily("Segoe UI Symbol"), FontWeight = FontWeights.ExtraLight, FontSize = 12, Foreground = new SolidColorBrush(Colors.Silver) });
                    hyperlink.NavigateUri = new Uri(Url);
                    ToolTipService.SetToolTip(tb, Url);
                    break;
                case Tools.NavType.Search:
                    ToolTipService.SetToolTip(tb, string.Format("Rechercher {0}", NavParameter));
                    hyperlink.Click += (s, e) =>
                        {
                            var context = tb.DataContext as IHasMainNavigationService;
                            context.NavigationService.Navigate("SearchResult", NavParameter);
                        };
                    break;
                case Tools.NavType.Game:
                    ToolTipService.SetToolTip(tb, "Naviguer vers la fiche du jeu");
                    hyperlink.Click += (s, e) =>
                    {
                        var context = tb.DataContext as IHasMainNavigationService;
                        context.NavigationService.Navigate("DetailGame", NavParameter);
                    };
                    break;
                case Tools.NavType.Preview:
                    ToolTipService.SetToolTip(tb, "Naviguer vers l'aperçu");
                    hyperlink.Click += (s, e) =>
                    {
                        var context = tb.DataContext as IHasMainNavigationService;
                        context.NavigationService.Navigate("PreviewGame", NavParameter);
                    };
                    break;
                case Tools.NavType.News:
                    ToolTipService.SetToolTip(tb, "Naviguer vers l'actualité");
                    hyperlink.Click += async (s, e) =>
                    {
                        var context = tb.DataContext as NewsWrapper;
                        if(context != null)
                        {
                            await ((NewsListPageViewModel)context.Parent).SelectNewsByIdAsync((int)NavParameter);
                        }
                        else
                        {
                            //(IHasMainNavigationService(context)).
                        }
                        //if (context is DetailNewsPageViewModel)
                        //{
                        //    var detailContext = context as DetailNewsPageViewModel;
                            
                        //    // TODO
                        //    //detailContext.Parent.NewsNavigationService.Navigate("DetailNews", NavParameter);
                        //}
                        //else
                        //{
                        //    context.GetMainNavigationService().Navigate("NewsList", NavParameter);
                        //}
                    };
                    break;
                case Tools.NavType.Test:
                    ToolTipService.SetToolTip(tb, "Naviguer vers le test");
                    hyperlink.Click += (s, e) =>
                    {
                        var context = tb.DataContext as IHasMainNavigationService;
                        context.NavigationService.Navigate("TestGame", NavParameter);
                    };
                    break;
                case Tools.NavType.Folder:
                    var param = (FolderPageNavigationParameter)NavParameter;
                    ToolTipService.SetToolTip(tb, param.FolderPage == 0 ? "Naviguer vers le sommaire du dossier" :
                        string.Format("Naviguer vers la page {0} du dossier", param.FolderPage));

                    hyperlink.Click += (s, e) =>
                    {
                        // TODO
                        //var context = tb.DataContext as PageBaseViewModel;
                        //if (context is DetailFolderPageViewModel)
                        //{
                        //    var detailContext = context as DetailFolderPageViewModel;
                        //    var parameter = SerializerHelper.Serialize<FolderPageNavigationParameter>(param);
                        //    detailContext.Parent.FolderNavigationService.Navigate("DetailFolder", parameter);
                        //}
                        //else
                        //{
                        //    context.GetMainNavigationService().Navigate("Folder", param.FolderId);
                        //}
                    };
                    break;
            }
     
            
            var UIinline = new InlineUIContainer();
            UIinline.Child = tb;
            return UIinline;
        }
    }
    #endregion
}
